﻿using UnityEngine;
using UnityEditor;
using UnityEngine.U2D;
using UnityEditor.U2D;
using System.IO;
using System.Collections.Generic;
using UnityEditor.Sprites;
using System.Reflection;

namespace NRatel.TextureUnpacker
{
    // 由于图集打包生效，必须通过手动点击 Inspector 面板上的 "Pack Preview" 完成
    // 故生成动画和生成图集不是放在一个操作完成，
    // 而是：生成图集->"Pack Preview"->重新点击plist文件创建动画
    public class EditorMain
    {
        [MenuItem("Assets/MyTools/Build Sprite Atlas")]
        public static void Start()
        {
            string selectionPath = AssetDatabase.GetAssetPath(Selection.activeObject);
            if (!selectionPath.EndsWith(".plist"))
            {
                EditorUtility.DisplayDialog("Error", "Please select a plist file!", "OK", "");
                return;
            }

            // App 只是一个带路径的空壳，因为 app.Save() 方法需要用路径
            //strPlistPath : "Assets/Resources/anim-cannon-fire/anim-cannon-fire.plist";
            string strPlistPath = selectionPath.Replace("\\", "/");
            App app = new App(strPlistPath);
            // 散图路径，参照 Core.cs
            string texturePath = app.GetSaveDir() + "/RestoredPngs";
            texturePath = texturePath.Replace("\\", "/");

            //strPlistPath : anim-cannon-fire
            //plistRootPath : Assets/Resources/anim-cannon-fire
            int name_beg_idx = strPlistPath.LastIndexOf("/");
            int name_end_idx = strPlistPath.IndexOf(".plist");
            string plistName = strPlistPath.Substring(name_beg_idx + 1, name_end_idx - name_beg_idx - 1);
            string plistRootPath = strPlistPath.Substring(0, name_beg_idx);

            // 切割成碎图
            SplitTexture(app);

            // 创建图集
            AutoSetAtlasContents(plistRootPath, texturePath, plistName);

            //模拟打包
            //ClickPackAltas(plistRootPath, plistName);

            // 根据图集创建动画
            //CreateAnim(plistRootPath, plistName);
        }


        // 切割成碎图
        private static void SplitTexture(App app)
        {
            string strPlistPath = app.PlistFilePath;

            string plistFilePath = strPlistPath;
            string pngFilePath = strPlistPath.Replace("plist", "png");

            // Function LoadFiles()
            Loader loader = null;
            Plist plist = null;
            Texture2D bigTexture = null;
            try
            {
                loader = Loader.LookingForLoader(plistFilePath);
                if (loader != null)
                {
                    plist = loader.LoadPlist(plistFilePath);
                    bigTexture = loader.LoadTexture(pngFilePath, plist.metadata);
                    Debug.Log("名称: " + plist.metadata.textureFileName + "\n类型: format_" + plist.metadata.format + "\n大小: " + plist.metadata.size.width + "*" + plist.metadata.size.height);
                }
                else
                {
                    Debug.Log("无法识别的plist类型!!!\n请联系作者");
                }
            }
            catch
            {
                Debug.Log("出错了!!!\n请联系作者\n↓");
            }

            //Function RegisterEvents()
            Core core = new Core(app);

            //Function Unpack()
            int total = plist.frames.Count;
            int count = 0;

            int frameSize = plist.frames.Count;
            for (int iFrame = 0; iFrame < frameSize; ++iFrame)
            {
                try
                {
                    core.Restore(bigTexture, plist.frames[iFrame]);

                    // 这种方式虽然打图集省资源，但是做出来的动画就不行了，会出现抖动
                    //core.JustSplit(bigTexture, plist.frames[iFrame]);

                    count += 1;
                    Debug.Log("进度：" + count + "/" + total + (count >= total ? "\n已完成！" : ""));
                }
                catch
                {
                    Debug.Log("出错了!!!\n请联系作者\n↓");
                }
                //yield return null;
            }//end for: iFrame

            // 碎图保存完毕，一定要刷新资源。否则后续操作无法进行。
            AssetDatabase.Refresh();
        }


        // 创建图集
        static void AutoSetAtlasContents(string _atlasPath, string _texturePath, string atlasName)
        {
            SpriteAtlas atlas = new SpriteAtlas();
            // 设置参数 可根据项目具体情况进行设置
            SpriteAtlasPackingSettings packSetting = new SpriteAtlasPackingSettings()
            {
                blockOffset = 1,
                enableRotation = false,
                enableTightPacking = false,
                padding = 2,
            };
            atlas.SetPackingSettings(packSetting);

            SpriteAtlasTextureSettings textureSetting = new SpriteAtlasTextureSettings()
            {
                readable = false,
                generateMipMaps = false,
                sRGB = true,
                filterMode = FilterMode.Bilinear,
            };
            atlas.SetTextureSettings(textureSetting);

            TextureImporterPlatformSettings platformSetting = new TextureImporterPlatformSettings()
            {
                maxTextureSize = 2048,
                format = TextureImporterFormat.Automatic,
                crunchedCompression = true,
                textureCompression = TextureImporterCompression.Compressed,
                compressionQuality = 50,
            };
            atlas.SetPlatformSettings(platformSetting);

            AssetDatabase.CreateAsset(atlas, _atlasPath + "/" + atlasName + ".spriteatlas");

            // 方式1、添加文件
            DirectoryInfo dir = new DirectoryInfo(_texturePath);
            // 这里我使用的是png图片，已经生成Sprite精灵了
            FileInfo[] files = dir.GetFiles("*.png");
            List<Sprite> listSprite = new List<Sprite>();
            foreach (FileInfo file in files)
            {
                string filePath = _texturePath + "/" + file.Name;
                TextureImporter texture = AssetImporter.GetAtPath(filePath) as TextureImporter;
                if (texture != null)
                {
                    texture.textureType = TextureImporterType.Sprite;
                    AssetDatabase.ImportAsset(filePath, ImportAssetOptions.ForceUpdate);
                    AssetDatabase.Refresh();

                    Sprite sprite = AssetDatabase.LoadAssetAtPath<Sprite>(filePath);
                    listSprite.Add(sprite);
                }
            }
            atlas.Add(listSprite.ToArray());

            // 方式2、添加文件夹(这种方式和方式1只需要一种即可)
            //Object obj = AssetDatabase.LoadAssetAtPath(_texturePath, typeof(Object));
            //atlas.Add(new[] { obj });

            AssetDatabase.SaveAssets();

            AssetDatabase.RemoveUnusedAssetBundleNames();
            //SpriteAtlas.DestroyImmediate(atlas);
            AssetDatabase.Refresh();

            // 在这直接打包，编辑器会崩溃
            //System.Threading.Thread.Sleep(5000);
            //SpriteAtlasUtility.PackAtlases(new SpriteAtlas[] { atlas }, EditorUserBuildSettings.activeBuildTarget);
            //AssetDatabase.Refresh();
        }


        [MenuItem("Assets/MyTools/Pack Altas")]
        public static void ClickPackAltas()
        {
            string selectionPath = AssetDatabase.GetAssetPath(Selection.activeObject);
            if (!selectionPath.EndsWith(".plist"))
            {
                EditorUtility.DisplayDialog("Error", "Please select a plist file!", "OK", "");
                return;
            }

            //strPlistPath : "Assets/Resources/anim-cannon-fire/anim-cannon-fire.plist";
            string strPlistPath = selectionPath.Replace("\\", "/");

            //strPlistPath : anim-cannon-fire
            //plistRootPath : Assets/Resources/anim-cannon-fire
            int name_beg_idx = strPlistPath.LastIndexOf("/");
            int name_end_idx = strPlistPath.IndexOf(".plist");
            string plistName = strPlistPath.Substring(name_beg_idx + 1, name_end_idx - name_beg_idx - 1);
            string plistRootPath = strPlistPath.Substring(0, name_beg_idx);


            string _atlasPath = plistRootPath;
            string atlasName = plistName;

            string atlasFullPath = _atlasPath + "/" + atlasName + ".spriteatlas";
            SpriteAtlas atlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(atlasFullPath);

            SpriteAtlasUtility.PackAtlases(new SpriteAtlas[] { atlas }, EditorUserBuildSettings.activeBuildTarget);
        }


        //根据图集创建动画：atlasPath 只包含路径，atlasName 不包含后缀名
        [MenuItem("Assets/MyTools/CreateAnimByPlist")]
        private static void CreateAnim(string atlasPath, string atlasName)
        {
            string atlasFullPath = atlasPath + "/" + atlasName + ".spriteatlas";
            atlasFullPath = atlasFullPath.Replace("\\", "/");
            SpriteAtlas atlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(atlasFullPath);

            int spriteSize = atlas.spriteCount;
            if (spriteSize <= 0)
            {
                Debug.Log("图集中未包含有效的精灵!!!\n请联系作者\n↓");
                return;
            }
            else if (spriteSize > 10000)
            {
                Debug.Log("图集大小超过10000!!!\n请联系作者\n↓");
                return;
            }

            //动画长度是按秒为单位，1/10就表示1秒切10张图片，根据项目的情况可以自己调节
            float frameTime = 1.0f / 10.0f;
            // 创建关键帧
            ObjectReferenceKeyframe[] keyFrames = new ObjectReferenceKeyframe[spriteSize];
            //逐帧插入动画
            for (int i = 0; i < spriteSize; ++i)
            {
                string num_str = i.ToString().PadLeft(4, '0');
                string spriteName = atlasName + "_" + num_str;
                Sprite sprite = atlas.GetSprite(spriteName);

                keyFrames[i] = new ObjectReferenceKeyframe();
                keyFrames[i].time = frameTime * i;
                keyFrames[i].value = sprite;
            }

            AnimationClip clip = new AnimationClip();
            clip.frameRate = 30;//动画帧率，30比较合适
            clip.name = atlasName;

            // 设置动画循环播放
            UnityEditor.AnimationClipSettings clipSetting = AnimationUtility.GetAnimationClipSettings(clip);
            clipSetting.loopTime = true;
            AnimationUtility.SetAnimationClipSettings(clip, clipSetting);

            EditorCurveBinding curveBinding = new EditorCurveBinding();
            curveBinding.type = typeof(SpriteRenderer);
            curveBinding.path = "";
            curveBinding.propertyName = atlasName;
            AnimationUtility.SetObjectReferenceCurve(clip, curveBinding, keyFrames);

            AssetDatabase.CreateAsset(clip, atlasPath + "/" + atlasName + ".anim");
            AssetDatabase.SaveAssets();
        }
    }
}